﻿/*
 * Created by SharpDevelop.
 * User: ratul
 * Date: 3/10/2010
 * Time: 11:04 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using H264Impl.NET.NAL;
using H264Impl.NET.Coding;

namespace H264Impl.NET.Decoder
{
	/// <summary>
	/// Description of VideoSequence.
	/// </summary>
		public class VideoSequence																					
		{
					
			
			public VideoSequence(UInt32 SeqParameterSetId)
			{
				this.SeqParameterSetId = SeqParameterSetId;
			}
			
			AccessUnit activeAccessUnit;
			
			public void parseSliceLayerWithoutPartitioningRBSP(NALUnit _NALUnit, BitStream RBSP)
			{
				UInt32 firstMbInSlice = ExpGolomb.getUnsignedIntegerElement(RBSP);
				UInt32 sliceType = ExpGolomb.getUnsignedIntegerElement(RBSP);
				UInt32 picParameterSetId = ExpGolomb.getUnsignedIntegerElement(RBSP);
				
				AccessUnit foundAccessUnit;
				if(!(accessUnitDictionary.TryGetValue((picParameterSetId), out foundAccessUnit)))
				{
					foundAccessUnit = new AccessUnit(this, picParameterSetId);
					accessUnitDictionary.Add((byte)(picParameterSetId), foundAccessUnit);
				}
				foundAccessUnit.parseSliceLayerWithoutPartitioningRBSP(_NALUnit, RBSP, firstMbInSlice, sliceType, picParameterSetId);
			}
			
			public void parseSequenceParameterExtensionRBSP(BitStream RBSP)
			{
				videoSequenceExtension = new VideoSequenceExtension();
				videoSequenceExtension. parseSequenceParameterExtensionRBSP(RBSP);
			}
			
			VideoSequenceExtension videoSequenceExtension;
			
			public void parsePictureParameterRBSP(BitStream RBSP, UInt32 picParameterSetId)
			{
				AccessUnit foundAccessUnit;
				if(!(accessUnitDictionary.TryGetValue((picParameterSetId), out foundAccessUnit)))
				{
					foundAccessUnit = new AccessUnit(this, picParameterSetId);
					accessUnitDictionary.Add((byte)(picParameterSetId), foundAccessUnit);
				}
				foundAccessUnit.parsePictureParameterRBSP(RBSP, picParameterSetId);
				activeAccessUnit = foundAccessUnit;

			}
			public void parseSequenceParameterRBSP(BitStream RBSP, byte profileIDC, bool constraintSet0Flag, bool constraintSet1Flag, bool constraintSet2Flag, bool constraintSet3Flag, bool constraintSet4Flag, UInt32 reservedZero3Bits, byte levelIDC)
			{
				this.profileIDC = profileIDC;
				this.constraintSet0Flag = constraintSet0Flag;
				this.constraintSet1Flag = constraintSet1Flag;
				this.constraintSet2Flag = constraintSet2Flag;
				this.constraintSet3Flag = constraintSet3Flag;
				this.constraintSet4Flag = constraintSet4Flag;
				this.reservedZero3Bits = reservedZero3Bits;
				this.levelIDC = levelIDC;
			
				if(profileIDC == 100 || profileIDC == 110 || profileIDC == 110  || profileIDC == 122 || profileIDC == 244 || profileIDC == 44 || profileIDC == 83 || profileIDC == 86 || profileIDC == 118)
				{
					chromaFormatIdc = (Byte)(RBSP.getBits(8));
					if(chromaFormatIdc == 3)
						separateColorPlaneFlag = RBSP.getBit();
					bitDepthLumaMinus8 = ExpGolomb.getUnsignedIntegerElement(RBSP);
					bitDepthChromaMinus8 = ExpGolomb.getUnsignedIntegerElement(RBSP);
					qpPrimeYZeroTransformBypassFlag = RBSP.getBit();
					seqScalingMatrixPresentFlag = RBSP.getBit();
				
					if(seqScalingMatrixPresentFlag)
					{
						seqScalingListPresentFlag = new bool[((chromaFormatIdc != 3) ? 8 : 12 )];
						for(int i=0; i<((chromaFormatIdc != 3) ? 8 : 12 ); i++) 
						{
							seqScalingListPresentFlag[i] = RBSP.getBit();
							if(seqScalingListPresentFlag[i])
							{
								if(i<6)
									;//scalingList();
								else 
									;//scalingList();
							}
						}
					}
					
				}
			
				log2MaxFrameNumMinus4 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				picOrderCntType = ExpGolomb.getUnsignedIntegerElement(RBSP);
				if(picOrderCntType == 0)
					log2MaxPicOrderCntLsbMinus4 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				else if(picOrderCntType == 1)
				{
					deltaPicOrderAlwaysZeroFlag = RBSP.getBit();
					offsetForNonRefPic = ExpGolomb.getSignedIntegerElement(RBSP);
					offsetForTopToBottomField = ExpGolomb.getSignedIntegerElement(RBSP);
					numRefFamesInPicOrderCntCycle = ExpGolomb.getUnsignedIntegerElement(RBSP);
					offsetForRefFrame = new List<Int32>((int)(numRefFamesInPicOrderCntCycle));
					for(int i=0;i<numRefFamesInPicOrderCntCycle; i++)
						offsetForRefFrame[0] = ExpGolomb.getSignedIntegerElement(RBSP);
				}
			
				maxNumRefFrames = ExpGolomb.getUnsignedIntegerElement(RBSP);
				gapsInFrameNumValueAllowedflag = RBSP.getBit();
				picWidthInMbsMinus1 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				picHeightInMapUnitsMinus1 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				
				frameMbsOnlyFlag = RBSP.getBit();
				if(!frameMbsOnlyFlag)
					mbAdaptiveFrameFieldFlag = RBSP.getBit();
					direct8x8InferenceFlag = RBSP.getBit();
				
				frameCroppingFlag = RBSP.getBit();
				if(frameCroppingFlag)
				{	
					frameCropLeftOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
					frameCropRightOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
					frameCropTopOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
					frameCropBottomOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
				}
				
				vuiParametersPresentFlag = RBSP.getBit();
				if(vuiParametersPresentFlag)
					vuiParameters(RBSP);
				
				rbspTrailingBits();
			}
		
			void rbspTrailingBits()
			{
					
			}
		
			private void vuiParameters(BitStream RBSP)
			{
				aspectRatioInfoPresentFlag = RBSP.getBit();
				if( aspectRatioInfoPresentFlag ) 
				{
					aspectRatioIdc = (Byte)(RBSP.getBits(8));
					if( aspectRatioIdc == (byte)(SampleRatioAspect.RExtended_SAR) )
					{
						sarWidth = (UInt16)(RBSP.getBits(16));
						sarHeight = (UInt16)(RBSP.getBits(16));
						
					}
				}
				overscanInfoPresentFlag = RBSP.getBit();
				if( overscanInfoPresentFlag )
					overscanAppropriateFlag = RBSP.getBit();
				videoSignalTypePresentFlag = RBSP.getBit();
				if( videoSignalTypePresentFlag )
				{
					videoFormat = (Byte)(RBSP.getBits(8));
					videoFullRangeFlag = RBSP.getBit();
					colourDescriptionpresentFlag = RBSP.getBit();
					if( colourDescriptionpresentFlag )
					{
						colourPrimaries = (Byte)(RBSP.getBits(8));
						transferCharacteristics = (Byte)(RBSP.getBits(8));
						matrixCoefficients = (Byte)(RBSP.getBits(8));
					}
				}
				
				chromaLocInfoPresentFlag = RBSP.getBit();
				if( chromaLocInfoPresentFlag ) 
				{
					chromaSampleLocTypeTopField = ExpGolomb.getUnsignedIntegerElement(RBSP);
					chromaSampleLocTypeBottomField = ExpGolomb.getUnsignedIntegerElement(RBSP);
				}	
				timingInfoPresentFlag = RBSP.getBit();
				if( timingInfoPresentFlag )
				{
					numUnitsinTick = RBSP.getBits(32);
					timeScale = RBSP.getBits(32);
					fixedFrameRateFlag = RBSP.getBit();
				}
				nalHrdParametersPresentFlag = RBSP.getBit();
				if( nalHrdParametersPresentFlag )
					hrd_parameters(RBSP);
				vclHrdParametersPresentFlag = RBSP.getBit();
				if( vclHrdParametersPresentFlag )
					hrd_parameters(RBSP);
				if( nalHrdParametersPresentFlag || vclHrdParametersPresentFlag )
					lowDelayHrdFlag = RBSP.getBit();
				picStructPresentFlag = RBSP.getBit();
				bitstreamRestrictionFlag = RBSP.getBit();
				if( bitstreamRestrictionFlag )
				{
					motionVectorsOverPicBoundariesFlag = RBSP.getBit();
					maxBytesPerPicDenom = ExpGolomb.getUnsignedIntegerElement(RBSP);
					maxBitsPerMbDenom = ExpGolomb.getUnsignedIntegerElement(RBSP);
					log2MaxMvLengthHorizontal = ExpGolomb.getUnsignedIntegerElement(RBSP);
					log2MaxMvLengthVertical = ExpGolomb.getUnsignedIntegerElement(RBSP);
					numReorderFrames = ExpGolomb.getUnsignedIntegerElement(RBSP);
					maxDecFrameBuffering = ExpGolomb.getUnsignedIntegerElement(RBSP);
				}	
						
			}
		
			enum SampleRatioAspect
			{
				R1_1 = 1,
				R12_11,
				R10_11,
				R16_11,
				R40_33,
				R24_11,
				R20_11,
				R32_11,
				R80_33,
				R18_11,
				R15_11,
				R64_33,
				R160_99,
				R4_3,
				R3_2,
				R2_1,
				RExtended_SAR = 255	
			}
		
			private void hrd_parameters(BitStream RBSP) 
			{
				cpbCntMinus1 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				bitRateScale = (Byte)(RBSP.getBits(8));
				cpbSizeScale = (Byte)(RBSP.getBits(8));
							
				bitRateValueMinus1 = new UInt32[cpbCntMinus1+1];
				cpbSizeValueMinus1 = new UInt32[cpbCntMinus1+1];
				cbrFlag = new bool[cpbCntMinus1+1];
				for( int SchedSelIdx = 0; SchedSelIdx <= cpbCntMinus1; SchedSelIdx++ ) {
					bitRateValueMinus1[ SchedSelIdx ] = ExpGolomb.getUnsignedIntegerElement(RBSP);
					cpbSizeValueMinus1[ SchedSelIdx ] = ExpGolomb.getUnsignedIntegerElement(RBSP);
					cbrFlag[ SchedSelIdx ] = RBSP.getBit();
				}
				initialCpbRemovalDelayLengthMinus1 = (Byte)(RBSP.getBits(8));
				cpbRemovalDelayLengthMinus1 = (Byte)(RBSP.getBits(8));
				dpbOutputDelayLengthMinus1 = (Byte)(RBSP.getBits(8));
				timeOffsetLength = (Byte)(RBSP.getBits(8));
			}	
			
			
			protected void scalingList(BitStream RBSP, out UInt32[] scalingList1, UInt32 sizeOfScalingList, out bool useDefaultScalingMatrixFlag )
			{ 
				UInt32 lastScale = 8;
				UInt32 nextScale = 8;
			
				useDefaultScalingMatrixFlag = false; 
			
				scalingList1 = new UInt32[sizeOfScalingList];
				for( int j = 0; j < sizeOfScalingList; j++ ) 
				{
					if( nextScale != 0 )
					{
						deltaScale = ExpGolomb.getSignedIntegerElement(RBSP);
						nextScale = (UInt32)(( lastScale + deltaScale + 256 ) % 256);
						if( j == 0 && nextScale == 0 )
							useDefaultScalingMatrixFlag = true;
						else
							useDefaultScalingMatrixFlag = false;
					}	
					scalingList1[j] = ( nextScale == 0 ) ? lastScale : nextScale;
					lastScale = scalingList1[j];
				}	
			}	
			
			public UInt32 getChromaFormatIdc()
			{
				return chromaFormatIdc;
			}
			
			public bool getSeparateColorPlaneFlag()
			{
				return separateColorPlaneFlag;
			}
			
			public UInt32 getLog2MaxFrameNumMinus4()
			{
				return log2MaxFrameNumMinus4;
			}
			
			public bool getFrameMbsOnlyFlag()
			{
				return frameMbsOnlyFlag;
			}
			
			public UInt32 getPicOrderCntType()
			{
				return picOrderCntType;
			}
			
			public UInt32 getLog2MaxPicOrderCntLsbMinus4()
			{
				return log2MaxPicOrderCntLsbMinus4;
			}
			
			public bool getDeltaPicOrderAlwaysZeroFlag()
			{
				return deltaPicOrderAlwaysZeroFlag;
			}
			
			byte profileIDC;
		
			bool constraintSet0Flag;
			bool constraintSet1Flag;
			bool constraintSet2Flag;
			bool constraintSet3Flag;
			bool constraintSet4Flag;
			UInt32 reservedZero3Bits;
			
			byte levelIDC;
			UInt32 SeqParameterSetId;
			UInt32 chromaFormatIdc;
			bool separateColorPlaneFlag;
			UInt32 bitDepthLumaMinus8;		
			UInt32 bitDepthChromaMinus8;
			bool qpPrimeYZeroTransformBypassFlag;
			bool seqScalingMatrixPresentFlag;
			bool[] seqScalingListPresentFlag;
			Int32 deltaScale;
			
			UInt32 log2MaxFrameNumMinus4;
			UInt32 picOrderCntType;
			UInt32 log2MaxPicOrderCntLsbMinus4;
			bool deltaPicOrderAlwaysZeroFlag;
			Int32 offsetForNonRefPic;
			Int32 offsetForTopToBottomField;
			UInt32 numRefFamesInPicOrderCntCycle;
			List<Int32> offsetForRefFrame;
			UInt32 maxNumRefFrames;
			bool gapsInFrameNumValueAllowedflag;
			UInt32 picWidthInMbsMinus1;
			UInt32 picHeightInMapUnitsMinus1;
		
			bool frameMbsOnlyFlag;
			bool mbAdaptiveFrameFieldFlag;
			bool direct8x8InferenceFlag;
			bool frameCroppingFlag;
			UInt32 frameCropLeftOffset;
			UInt32 frameCropRightOffset;
			UInt32 frameCropTopOffset;
			UInt32 frameCropBottomOffset;
			bool vuiParametersPresentFlag;
			
		
		
			//VUI parameters
			bool aspectRatioInfoPresentFlag;
			byte aspectRatioIdc;
			UInt16 sarWidth;
			UInt16 sarHeight;
			bool overscanInfoPresentFlag;
			bool overscanAppropriateFlag;
			bool videoSignalTypePresentFlag;
			byte videoFormat;
			bool videoFullRangeFlag;
			bool colourDescriptionpresentFlag;
			byte colourPrimaries;
			byte transferCharacteristics;
			byte matrixCoefficients;
			
			bool chromaLocInfoPresentFlag;
			UInt32 chromaSampleLocTypeTopField;
			UInt32 chromaSampleLocTypeBottomField;
			bool timingInfoPresentFlag;
			UInt32 numUnitsinTick;
			UInt32 timeScale;
			bool fixedFrameRateFlag;
			bool nalHrdParametersPresentFlag;
			bool vclHrdParametersPresentFlag;
			bool lowDelayHrdFlag;
			bool picStructPresentFlag;
			bool bitstreamRestrictionFlag;
			
			bool motionVectorsOverPicBoundariesFlag;
			UInt32 maxBytesPerPicDenom;
			UInt32 maxBitsPerMbDenom;
			UInt32 log2MaxMvLengthHorizontal;
			UInt32 log2MaxMvLengthVertical;
			UInt32 numReorderFrames;
			UInt32 maxDecFrameBuffering;
		
							
		
		
			//HRD parameters
			UInt32 cpbCntMinus1;
			byte bitRateScale;
			byte cpbSizeScale;
			UInt32[] bitRateValueMinus1;
			UInt32[] cpbSizeValueMinus1;
			bool[] cbrFlag;
			byte initialCpbRemovalDelayLengthMinus1;
			byte cpbRemovalDelayLengthMinus1;
			byte dpbOutputDelayLengthMinus1;
			byte timeOffsetLength;
				
			
			Dictionary<UInt32, AccessUnit> accessUnitDictionary = new Dictionary<UInt32, AccessUnit>();

				
			AccessUnit IDR;  //instantaneous decoding refresh
			List<Decoder.AccessUnit> NonIDRAccessUnitList;
		}
		
		
	}

